package org.jsola.hr.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.jsola.admin.entity.DictItemDO;
import org.jsola.cache.ICache;
import org.jsola.common.StrKit;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.*;
import org.jsola.hr.constant.CheckInPeopleConstant;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.ICheckInPeopleDAO;
import org.jsola.hr.dao.IEmpInfoDAO;
import org.jsola.hr.dto.*;
import org.jsola.hr.dto.excel.CheckInPeopleImportDTO;
import org.jsola.hr.entity.*;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.provider.IPermissionProviderService;
import org.jsola.hr.query.*;
import org.jsola.hr.service.*;
import org.jsola.hr.service.excel.CheckInPeopleImportListener;
import org.jsola.hr.vo.*;
import org.jsola.hr.vo.excel.CheckInPeopleExportVO;
import org.jsola.orm.filter.Order;
import org.jsola.permission.entity.RoleMemberDO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 预登记人员
 *
 * @author zhr
 */
@Service("hrCheckInPeopleServiceImpl")
@Slf4j
public class CheckInPeopleServiceImpl implements ICheckInPeopleService {

    @Autowired
    private ICheckInPeopleDAO checkInPeopleDAO;
    @Autowired
    private IEmpInfoService empInfoService;
    @Autowired
    private ICompanyService companyService;
    @Autowired
    private IChannelService channelService;
    @Autowired
    private IOperationEmpRecordService operationEmpRecordService;

    @Autowired
    private ICompanyAdditionalFieldsService companyAdditionalFieldsService;

    @Autowired
    private IEmpAdditionalFieldsService empAdditionalFieldsService;

    @Autowired
    private ICache cache;

    @Autowired
    private IEmpInfoDAO empInfoDAO;

    @Autowired
    private IPermissionProviderService permissionProviderService;

    @Autowired
    private IAdminProviderService adminProviderService;

    /**
     * 员工自定义字段类型-预登记
     */
    private static final Integer EMP_ADD_FIELD_TYPE_CHECK_IN = 2;

    @Override
    public CheckInPeopleListVO identificationCard(CheckInPeopleQuery checkInPeopleQuery, TokenUser tokenUser) {
        CheckInPeopleListVO checkInPeopleListVO = new CheckInPeopleListVO();
        List<String> idCardList = new ArrayList<>();
        List<CheckInPeopleVO> CheckInPeopleVOS = new ArrayList<>();
        for (String idCard : checkInPeopleQuery.getCardList()) {
            if (StringUtils.isEmpty(idCard)) {
                continue;
            }
            Example example = new Example(CheckInPeopleDO.class);
            example.and()
                    .andEqualTo("valid", true)
                    .andEqualTo("siteId", tokenUser.getSiteId())
                    .andEqualTo("source", "预登记");
            example.and().andEqualTo("idcard", idCard);
            if (checkInPeopleQuery.getIsBatchUpdateStatus() != null && checkInPeopleQuery.getIsBatchUpdateStatus()) {
                List<Integer> integers = new ArrayList<>();
                integers.add(1);
                integers.add(2);
                integers.add(3);
                example.and().andIn("status", integers);
            }
            CheckInPeopleDO checkInPeopleDO = checkInPeopleDAO.selectOneByExample(example);
            if (checkInPeopleDO == null) {
                idCardList.add(idCard);
            } else {
                if (CheckInPeopleVOS.removeIf(checkInPeopleVO ->
                        checkInPeopleVO.getId().equals(checkInPeopleDO.getId()))) {
                    idCardList.add(idCard);
                }
                CheckInPeopleVOS.add(checkInPeopleDO.to(CheckInPeopleVO.class));
            }
        }
        checkInPeopleListVO.setCheckInPeopleVOList(CheckInPeopleVOS);
        checkInPeopleListVO.setIdCardList(idCardList);
        return checkInPeopleListVO;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer batchUpdate(CheckInPeopleUpdateDTO checkInPeopleUpdateDTO, TokenUser tokenUser) {
        List<String> checkInIds = checkInPeopleUpdateDTO.getCheckInIds();
        int count = 0;
        //批量修改无渠道
        if (!StringUtils.isEmpty(checkInPeopleUpdateDTO.getChannelId()) && "无渠道".equals(checkInPeopleUpdateDTO.getChannelId())) {
            for (String checkInId : checkInIds) {
                CheckInPeopleVO checkInPeopleVO = selectById(checkInId, tokenUser.getSiteId());
                checkInPeopleVO.setChannelId(null);
                count += updateIncludeNull(checkInPeopleVO.to(CheckInPeopleDO.class), tokenUser);

                //花名册同步更新
                if (!StringUtils.isEmpty(checkInPeopleVO.getPhone())) {
                    EmpInfoDO empInfoDO = empInfoService.selectByPhone(checkInPeopleVO.getPhone(), tokenUser);
                    if (empInfoDO != null) {
                        empInfoDO.setChannelId(null);
                        Example example = new Example(EmpInfoDO.class);
                        example.and()
                                .andEqualTo("id", empInfoDO.getId());
                        EmpInfoDO empInfoDO1 = empInfoDAO.selectOneByExample(example);
                        ParamException.notNull(empInfoDO1, "id不正确，没有找到该数据");
                        // 设置siteId及其他属性
                        empInfoDO.setSiteId(empInfoDO1.getSiteId());
                        empInfoDO.setValid(empInfoDO1.getValid());
                        empInfoDO.setGmtModified(new Date());
                        empInfoDO.setGmtCreate(empInfoDO1.getGmtCreate());
                        empInfoDO.setCreateUserId(empInfoDO1.getCreateUserId());
                        empInfoDO.setModifiedUserId(tokenUser.getUserId());
                        empInfoDAO.updateByExample(empInfoDO, example);
                    }

                }
            }
        } else if (checkInPeopleUpdateDTO.getStatus() != null || !StringUtils.isEmpty(checkInPeopleUpdateDTO.getChannelId())) {
            for (String checkInId : checkInIds) {
                CheckInPeopleVO checkInPeopleVO = selectById(checkInId, tokenUser.getSiteId());
                CheckInPeopleUpdateDTO checkInPeopleUpdateDTO1 = new CheckInPeopleUpdateDTO();
                checkInPeopleUpdateDTO1.setId(checkInId);
                if (checkInPeopleUpdateDTO.getStatus() != null) {
                    checkInPeopleUpdateDTO1.setStatus(checkInPeopleUpdateDTO.getStatus());
                } else if (!StringUtils.isEmpty(checkInPeopleUpdateDTO.getChannelId())) {
                    checkInPeopleUpdateDTO1.setChannelId(checkInPeopleUpdateDTO.getChannelId());
                }
                count += update(checkInPeopleUpdateDTO1, tokenUser);

                //花名册同步更新
                if (!StringUtils.isEmpty(checkInPeopleVO.getPhone())) {
                    EmpInfoDO empInfoDO = empInfoService.selectByPhone(checkInPeopleVO.getPhone(), tokenUser);
                    if (empInfoDO != null) {
                        empInfoDO.setChannelId(checkInPeopleUpdateDTO.getChannelId());
                        Example example = new Example(EmpInfoDO.class);
                        example.and()
                                .andEqualTo("id", empInfoDO.getId());
                        EmpInfoDO empInfoDO1 = empInfoDAO.selectOneByExample(example);
                        ParamException.notNull(empInfoDO1, "id不正确，没有找到该数据");
                        // 设置siteId及其他属性
                        empInfoDO.setSiteId(empInfoDO1.getSiteId());
                        empInfoDO.setValid(empInfoDO1.getValid());
                        empInfoDO.setGmtModified(new Date());
                        empInfoDO.setGmtCreate(empInfoDO1.getGmtCreate());
                        empInfoDO.setCreateUserId(empInfoDO1.getCreateUserId());
                        empInfoDO.setModifiedUserId(tokenUser.getUserId());
                        empInfoDAO.updateByExample(empInfoDO, example);
                    }

                }
            }
        }

        return count;
    }

    @Override
    public InputStream checkTodayAddExport(StatisicsPageEmpExportQuery statisicsPageEmpExportQuery, TokenUser tokenUser) {
        //制作表头
        List<List<String>> list = new ArrayList<>();
        for (int i = 0; i < 16; i++) {
            ArrayList<String> list1 = new ArrayList<>();
            if (i == 0) {
                list1.add("人员姓名");
            } else if (i == 1) {
                list1.add("手机号");
            } else if (i == 2) {
                list1.add("身份证号");
            } else if (i == 3) {
                list1.add("用工单位");
            } else if (i == 4) {
                list1.add("渠道来源");
            } else if (i == 5) {
                list1.add("人员状态");
            } else if (i == 6) {
                list1.add("录入人");
            } else if (i == 7) {
                list1.add("录入方式");
            } else if (i == 8) {
                list1.add("名族");
            } else if (i == 9) {
                list1.add("出生年月");
            } else if (i == 10) {
                list1.add("住址");
            } else if (i == 11) {
                list1.add("签发机关");
            } else if (i == 12) {
                list1.add("开始期限");
            } else if (i == 13) {
                list1.add("结束期限");
            } else if (i == 14) {
                list1.add("备注");
            } else {
                list1.add("登记时间");
            }
            list.add(list1);
        }
        Page<CheckInPeopleListVO> checkInPeopleListVOPage = operationEmpRecordService.queryPageList(statisicsPageEmpExportQuery.getOperationEmpRecordQuery(), tokenUser);
        List<CheckInPeopleListVO> checkInPeopleVOList = checkInPeopleListVOPage.getEntities();
        //数据
        List<List<String>> dataList = new ArrayList<>();
        for (int i = 0; i < checkInPeopleVOList.size(); i++) {
            List<String> dataInfoList = new ArrayList<>();
            dataInfoList.add(checkInPeopleVOList.get(i).getName());
            dataInfoList.add(checkInPeopleVOList.get(i).getPhone());
            dataInfoList.add(checkInPeopleVOList.get(i).getIdcard());
            dataInfoList.add(checkInPeopleVOList.get(i).getCompanyName());
            dataInfoList.add(checkInPeopleVOList.get(i).getChannelName());
            Integer status = checkInPeopleVOList.get(i).getStatus();
            if (status != null) {
                if (status == 1) {
                    dataInfoList.add("已接到");
                } else if (status == 2) {
                    dataInfoList.add("已安排");
                } else if (status == 3) {
                    dataInfoList.add("已面试");
                } else if (status == 4) {
                    dataInfoList.add("已入职");
                } else if (status == 5) {
                    dataInfoList.add("已离职");
                } else if (status == 6) {
                    dataInfoList.add("待入职");
                } else if (status == 7) {
                    dataInfoList.add("未到岗");
                }
            } else {
                dataInfoList.add(" ");
            }
            dataInfoList.add(checkInPeopleVOList.get(i).getInputName());
            Integer sourceType = checkInPeopleVOList.get(i).getSourceType();
            if (sourceType != null) {
                if (sourceType == 1) {
                    dataInfoList.add("网页端");
                } else if (sourceType == 2) {
                    dataInfoList.add("手机端");
                } else if (sourceType == 3) {
                    dataInfoList.add("用工单位");
                }
            } else {
                dataInfoList.add(" ");
            }
            dataInfoList.add(checkInPeopleVOList.get(i).getNation());
            dataInfoList.add(checkInPeopleVOList.get(i).getBirthday());
            dataInfoList.add(checkInPeopleVOList.get(i).getAddress());
            dataInfoList.add(checkInPeopleVOList.get(i).getIssuedBy());
            dataInfoList.add(checkInPeopleVOList.get(i).getStartDate());
            dataInfoList.add(checkInPeopleVOList.get(i).getEndDate());
            dataInfoList.add(checkInPeopleVOList.get(i).getRemark());
            dataInfoList.add(DateUtil.format(checkInPeopleVOList.get(i).getGmtCreate(), "yyyy/MM/dd HH:mm:ss"));
            dataList.add(dataInfoList);
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        EasyExcel.write(outputStream)
                .head(list)
                .registerWriteHandler(new CustomCellWriteHandler())
                .sheet("今日新增")
                .doWrite(dataList);

        return new ByteArrayInputStream(outputStream.toByteArray());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public CheckInPeopleVO save(CheckInPeopleAddDTO checkInPeopleAddDTO, TokenUser tokenUser) {
        // 员工端小程序deviceType
        List<DictItemDO> empDictItem = adminProviderService.selectByDictCode("1217");
        List<String> empDeviceType = empDictItem.stream()
                .map(DictItemDO::getDictItemValue).collect(Collectors.toList());
        // 管理端小程序deviceType
        List<DictItemDO> adminDictItem = adminProviderService.selectByDictCode("1218");
        List<String> adminDeviceType = adminDictItem.stream()
                .map(DictItemDO::getDictItemValue).collect(Collectors.toList());
        // PC端deviceType
        List<DictItemDO> pcDictItem = adminProviderService.selectByDictCode("1219");
        List<String> pcDeviceType = pcDictItem.stream()
                .map(DictItemDO::getDictItemValue).collect(Collectors.toList());
        if (checkInPeopleAddDTO.getType() == null) {
            checkInPeopleAddDTO.setType(1);
        }
        // 查询该手机号是否已添加
        if (StrKit.isNotEmpty(checkInPeopleAddDTO.getPhone())) {
            Example example = new Example(CheckInPeopleDO.class);
            example.and()
                    .andEqualTo("valid", true)
                    .andEqualTo("siteId", tokenUser.getSiteId())
                    .andEqualTo("phone", checkInPeopleAddDTO.getPhone());
            ParamException.isTrue(CollectionUtils.isEmpty(checkInPeopleDAO.selectByExample(example)), "该手机号已存在，请勿重复添加");
        }
        // 转DO
        CheckInPeopleDO checkInPeopleDO = checkInPeopleAddDTO.to(CheckInPeopleDO.class);
        // 保存
        if (checkInPeopleDO.getWorkStatus() == null) {
            checkInPeopleDO.setWorkStatus(CheckInPeopleConstant.WORK_STATUS_REGISTER);
        }
        // 如果身份证正反面都不为空，认为是实名认证通过
        if (StrKit.isNotEmpty(checkInPeopleDO.getIdCardFront()) && StrKit.isNotEmpty(checkInPeopleDO.getIdCardBack())) {
            checkInPeopleDO.setVerified(true);
        }
        checkInPeopleDO = save(checkInPeopleDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 保存自定义字段值
        saveAdditionalField(checkInPeopleAddDTO.getAddEmpFieldList(), checkInPeopleDO.getId(), tokenUser);
        // 动态码录入员工列表
        addByCode(checkInPeopleAddDTO.getCode(), checkInPeopleDO);
        try {
            if (!StringUtils.isEmpty(checkInPeopleAddDTO.getSource()) && !HrConstants.HUW.equals(checkInPeopleAddDTO.getSource())) {
                if (StringUtils.isEmpty(checkInPeopleAddDTO.getFlag())) {
                    HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
                    String deviceType = request.getHeader("devicetype");
                    OperationEmpRecordAddDTO operationEmpRecordAddDTO = new OperationEmpRecordAddDTO();
                    operationEmpRecordAddDTO.setQueryType(1);
                    operationEmpRecordAddDTO.setCheckInId(checkInPeopleDO.getId());
                    operationEmpRecordAddDTO.setEmpStatus(1);
                    if (pcDeviceType.contains(deviceType)) {
                        operationEmpRecordAddDTO.setSourceType(1);
                        operationEmpRecordAddDTO.setSourceTypeInfo("PC预登记");
                        operationEmpRecordAddDTO.setInputUserId(tokenUser.getUserId());
                    } else if (adminDeviceType.contains(deviceType)) {
                        operationEmpRecordAddDTO.setSourceType(2);
                        operationEmpRecordAddDTO.setSourceTypeInfo("小程序管理端预登记");
                        operationEmpRecordAddDTO.setInputUserId(tokenUser.getUserId());
                    } else if (empDeviceType.contains(deviceType)) {
                        operationEmpRecordAddDTO.setSourceType(2);
                        operationEmpRecordAddDTO.setSourceTypeInfo("小程序预登记");
                        operationEmpRecordAddDTO.setInputUserId(checkInPeopleAddDTO.getUserId());
                    }

                    operationEmpRecordAddDTO.setMethodPath("org.jsola.hr.web.CheckInPeopleServiceImpl.save");
                    operationEmpRecordService.save(operationEmpRecordAddDTO, tokenUser);
                }
            }
        } catch (Exception e) {
            log.error("员工记录日志错误");
        }

        return checkInPeopleDO.to(CheckInPeopleVO.class);
    }

    /**
     * 保存自定义字段值
     *
     * @param addEmpFieldList 自定义字段列表
     * @param tokenUser       当前用户
     */
    private void saveAdditionalField(List<AddEmpFieldDTO> addEmpFieldList, String checkInId, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(addEmpFieldList)) {
            return;
        }
        String companyId = HrConstants.ADD_FIELD_COMPANY_SITE;
        List<Long> idList = addEmpFieldList.parallelStream().map(AddEmpFieldDTO::getId).collect(Collectors.toList());
        List<CompanyAdditionalFieldsDO> companyAdditionalFieldsDOS = companyAdditionalFieldsService.selectByIdList(idList, tokenUser);
        // id-字段 Map
        Map<Long, CompanyAdditionalFieldsDO> idFieldsMap = companyAdditionalFieldsDOS.parallelStream()
                .collect(Collectors.toMap(CompanyAdditionalFieldsDO::getId, v -> v));
        for (AddEmpFieldDTO addEmpFieldDTO : addEmpFieldList) {
            CompanyAdditionalFieldsDO companyAdditionalFieldsDO = idFieldsMap.get(addEmpFieldDTO.getId());
            if (companyAdditionalFieldsDO == null) {
                throw new ParamException("自定义字段【" + addEmpFieldDTO.getFieldName() + "】不存在");
            }

            if (Boolean.FALSE.equals(companyAdditionalFieldsDO.getIsOpen())) {
                throw new ParamException("自定义字段【" + companyAdditionalFieldsDO.getFieldName() + "】未开启，无需填写");
            }
            // 校验字段长度
            EmpFieldModuleCodeKit.checkFieldType(companyAdditionalFieldsDO.getFieldType(), companyAdditionalFieldsDO.getFieldName(), addEmpFieldDTO.getContent());
            EmpAdditionalFieldsAddDTO empAdditionalFieldsAddDTO = new EmpAdditionalFieldsAddDTO();
            empAdditionalFieldsAddDTO.setModuleCode(companyAdditionalFieldsDO.getModuleCode());
            empAdditionalFieldsAddDTO.setCompanyId(companyId);
            empAdditionalFieldsAddDTO.setFieldId(companyAdditionalFieldsDO.getId());
            empAdditionalFieldsAddDTO.setContent(addEmpFieldDTO.getContent());
            empAdditionalFieldsAddDTO.setEmpId(checkInId);
            // 类型；1：员工 2：预登记人员
            empAdditionalFieldsAddDTO.setType(2);
            empAdditionalFieldsService.save(empAdditionalFieldsAddDTO, tokenUser);
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public CheckInPeopleVO saveNoPE(CheckInPeopleAddDTO checkInPeopleAddDTO, TokenUser tokenUser) {
        // 查询该手机号是否已添加
        if (StrKit.isNotEmpty(checkInPeopleAddDTO.getPhone())) {
            Example example = new Example(CheckInPeopleDO.class);
            example.and()
                    .andEqualTo("valid", true)
                    .andEqualTo("siteId", tokenUser.getSiteId())
                    .andEqualTo("phone", checkInPeopleAddDTO.getPhone());
            if (!CollectionUtils.isEmpty(checkInPeopleDAO.selectByExample(example))) {
                return null;
            }
        }
        // 转DO
        CheckInPeopleDO checkInPeopleDO = checkInPeopleAddDTO.to(CheckInPeopleDO.class);
        // 保存
        if (checkInPeopleDO.getWorkStatus() == null) {
            checkInPeopleDO.setWorkStatus(CheckInPeopleConstant.WORK_STATUS_REGISTER);
        }
        checkInPeopleDO = save(checkInPeopleDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 动态码录入员工列表
        addByCode(checkInPeopleAddDTO.getCode(), checkInPeopleDO);
        try {
            if (checkInPeopleDO != null) {
                if (StringUtils.isEmpty(checkInPeopleAddDTO.getCode())) {
                    OperationEmpRecordAddDTO operationEmpRecordAddDTO = new OperationEmpRecordAddDTO();
                    operationEmpRecordAddDTO.setEmpStatus(1);
                    operationEmpRecordAddDTO.setQueryType(1);
                    operationEmpRecordAddDTO.setInputUserId(tokenUser.getUserId());
                    operationEmpRecordAddDTO.setCheckInId(checkInPeopleDO.getId());
                    operationEmpRecordAddDTO.setSourceType(1);
                    operationEmpRecordAddDTO.setSourceTypeInfo("PC预登记");
                    operationEmpRecordAddDTO.setMethodPath("org.jsola.hr.web.CheckInPeopleServiceImpl.saveNoPE");
                    operationEmpRecordService.save(operationEmpRecordAddDTO, tokenUser);
                }
            }
        } catch (Exception e) {
            log.error("员工记录异常");
        }

        return checkInPeopleDO.to(CheckInPeopleVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<CheckInPeopleVO> importCheckInPeople(File file, TokenUser tokenUser) {
        CheckInPeopleImportListener checkInPeopleImportListener = new CheckInPeopleImportListener();
        checkInPeopleImportListener.setTokenUser(tokenUser);
        checkInPeopleImportListener.setParseOnly(false);
        // 读取excel入库
        EasyExcel.read(file, CheckInPeopleImportDTO.class, checkInPeopleImportListener).sheet().doRead();
        if (checkInPeopleImportListener.getSuccessCount() == 0) {
            throw new ParamException("没有数据导入成功，请检查数据是否有误!");
        }
        return checkInPeopleImportListener.getFailCheckInPeopleList();
    }


    /**
     * 动态码录入预登记人员列表
     */
    private void addByCode(String code, CheckInPeopleDO checkInPeopleDO) {
        if (StrKit.isEmpty(code)) {
            return;
        }
        String key = CacheKeyKit.getDynamicCode(code);
        DynamicCodeVO dynamicCodeVO = cache.get(key);
        if (Objects.isNull(dynamicCodeVO)) {
            return;
        }
        // 不是添加预登记的动态码就不记录
        if (!HrConstants.TYPE_CHECKIN.equals(dynamicCodeVO.getType())) {
            return;
        }
        List<CheckInPeopleDO> list;
        if (CollectionUtils.isEmpty(dynamicCodeVO.getCheckInPeopleDOList())) {
            list = new ArrayList<>();
        } else {
            list = dynamicCodeVO.getCheckInPeopleDOList();
        }
        list.add(checkInPeopleDO);
        dynamicCodeVO.setCheckInPeopleDOList(list);
        // 有效时间
        long ttl = cache.ttl(key);
        // key失效
        if (ttl != -1 && ttl != -2) {
            // 因为是重新写入,有效时间可能会稍微多一点
            cache.set(key, dynamicCodeVO, ttl * 1000);
            log.info("通过动态码添加一位预登记人员,code:{},人员信息:{}", code, JSON.toJSONString(checkInPeopleDO));
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(CheckInPeopleUpdateDTO checkInPeopleUpdateDTO, TokenUser tokenUser) {
        // 判断是否手机号已存在
        CheckInPeopleDO checkInPeopleOld = this.selectDOById(checkInPeopleUpdateDTO.getId(), tokenUser.getSiteId());
        ParamException.notNull(checkInPeopleOld, "ID对应的预登记人员不存在或已删除，请刷新重试");
        String phone = checkInPeopleUpdateDTO.getPhone();
        if (StrKit.isNotEmpty(phone) && !phone.equals(checkInPeopleOld.getPhone())) {
            ParamException.isNull(this.selectByPhone(phone, tokenUser.getSiteId()), "该手机号已存在，修改失败!");
        }
        // 修改自定义字段
        updateAdditionalField(checkInPeopleUpdateDTO.getId(), checkInPeopleUpdateDTO.getAddEmpFieldList(), tokenUser);
        //转DO
        CheckInPeopleDO checkInPeopleDO = checkInPeopleUpdateDTO.to(CheckInPeopleDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(checkInPeopleDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    /**
     * 修改自定义字段值
     *
     * @param checkInPeopleId 预登记人员id
     * @param addEmpFieldList 自定义字段列表
     * @param tokenUser       当前用户
     */
    private void updateAdditionalField(String checkInPeopleId, List<AddEmpFieldDTO> addEmpFieldList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(addEmpFieldList)) {
            return;
        }
        // id-字段 Map
        for (AddEmpFieldDTO addEmpFieldDTO : addEmpFieldList) {
            Long fieldId = addEmpFieldDTO.getFieldId();
            CompanyAdditionalFieldsVO companyAdditionalFieldsVO = companyAdditionalFieldsService.selectById(fieldId,
                    tokenUser.getSiteId());
            if (companyAdditionalFieldsVO != null) {
                // 校验字段长度
                EmpFieldModuleCodeKit.checkFieldType(companyAdditionalFieldsVO.getFieldType(),
                        companyAdditionalFieldsVO.getFieldName(), addEmpFieldDTO.getContent());
            }
            Long addEmpFieldDTOId = addEmpFieldDTO.getId();
            if (addEmpFieldDTOId == null) {
                // 新建员工自定义信息
                EmpAdditionalFieldsAddDTO addDTO = new EmpAdditionalFieldsAddDTO();
                addDTO.setFieldId(addEmpFieldDTO.getFieldId());
                addDTO.setContent(addEmpFieldDTO.getContent());
                addDTO.setModuleCode(addEmpFieldDTO.getModuleCode());
                addDTO.setEmpId(checkInPeopleId);
                addDTO.setType(EMP_ADD_FIELD_TYPE_CHECK_IN);
                addDTO.setCompanyId(HrConstants.ADD_FIELD_COMPANY_SITE);
                empAdditionalFieldsService.save(addDTO, tokenUser);
            } else {
                // 更新自定义信息
                EmpAdditionalFieldsUpdateDTO updateDTO = new EmpAdditionalFieldsUpdateDTO();
                updateDTO.setId(addEmpFieldDTOId);
                updateDTO.setContent(addEmpFieldDTO.getContent());
                empAdditionalFieldsService.update(updateDTO, tokenUser);
            }
        }
    }

    @Override
    public int updateIncludeNull(CheckInPeopleDO checkInPeopleDO, TokenUser tokenUser) {
        // 根据主键查找
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("id", checkInPeopleDO.getId());
        CheckInPeopleDO checkInPeople = checkInPeopleDAO.selectOneByExample(example);
        ParamException.notNull(checkInPeople, "id不正确，没有找到该数据");
        // 设置siteId及其他属性
        checkInPeopleDO.setSiteId(checkInPeople.getSiteId());
        checkInPeopleDO.setValid(checkInPeople.getValid());
        checkInPeopleDO.setGmtModified(new Date());
        checkInPeopleDO.setGmtCreate(checkInPeople.getGmtCreate());
        checkInPeopleDO.setCreateUserId(checkInPeople.getCreateUserId());
        checkInPeopleDO.setModifiedUserId(tokenUser.getUserId());
        return checkInPeopleDAO.updateByExample(checkInPeopleDO, example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... checkInPeopleIds) {
        boolean flag = true;
        //删除员工记录
        for (String checkInPeopleId : checkInPeopleIds) {
            OperationEmpRecordQuery operationEmpRecordQuery = new OperationEmpRecordQuery();
            operationEmpRecordQuery.setCheckInId(checkInPeopleId);
            List<OperationEmpRecordListVO> select = operationEmpRecordService.select(operationEmpRecordQuery, tokenUser.getSiteId());
            for (OperationEmpRecordListVO operationEmpRecordListVO : select) {
                operationEmpRecordService.deleteByIds(tokenUser, operationEmpRecordListVO.getId());
            }
        }

        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) checkInPeopleIds);
    }

    @Override
    public int deleteByPhone(TokenUser tokenUser, String phone) {
        CheckInPeopleDO checkInPeopleDO = selectByPhone(phone, tokenUser.getSiteId());
        if (checkInPeopleDO != null) {
            return this.deleteByIds(tokenUser, checkInPeopleDO.getId());
        }
        return 0;
    }


    @Override
    public CheckInPeopleVO selectById(String checkInPeopleId, String siteId) {
        CheckInPeopleDO checkInPeopleDO = selectDOById(checkInPeopleId, siteId);
        if (checkInPeopleDO == null) {
            return null;
        }
        return checkInPeopleDO.to(CheckInPeopleVO.class);
    }

    @Override
    public List<CheckInPeopleListVO> select(CheckInPeopleQuery checkInPeopleQuery, String siteId) {
        List<CheckInPeopleDO> checkInPeopleDOList = selectDO(checkInPeopleQuery, siteId);
        if (CollectionUtils.isEmpty(checkInPeopleDOList)) {
            return checkInPeopleDOList == null ? null : new ArrayList<>();
        }
        return checkInPeopleDOList.stream()
                .map(checkInPeopleDO -> checkInPeopleDO.to(CheckInPeopleListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(CheckInPeopleQuery checkInPeopleQuery, String siteId) {
        Example example = buildExample(checkInPeopleQuery, siteId);
        return checkInPeopleDAO.selectCountByExample(example);
    }

    @Override
    public Map<String, Integer> selectCount(List<String> channelIdList, String siteId) {
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("channelId", channelIdList);
        List<CheckInPeopleDO> checkInPeopleDOS = checkInPeopleDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(checkInPeopleDOS)) {
            return null;
        }
        Map<String, Integer> countMap = new HashMap<>(16);
        Map<String, List<CheckInPeopleDO>> listMap = checkInPeopleDOS.parallelStream()
                .collect(Collectors.groupingBy(CheckInPeopleDO::getChannelId));
        listMap.forEach((k, v) -> countMap.put(k, v.size()));
        return countMap;
    }

    @Override
    public Page<CheckInPeopleListVO> selectPage(CheckInPeopleQuery checkInPeopleQuery, String siteId) {
        Example example = buildExample(checkInPeopleQuery, siteId);
        Page<CheckInPeopleDO> page = checkInPeopleDAO.selectPageByExample(example,
                checkInPeopleQuery.getPageNo(),
                checkInPeopleQuery.getPageSize());
        return page.to(CheckInPeopleListVO.class);
    }

    @Override
    public Page<CheckInPeopleListVO> selectPageForMini(CheckInPeopleQuery checkInPeopleQuery, TokenUser tokenUser) {
        // 先判断当前登录人的角色
        String channelId = checkCurrentRole(tokenUser);
        if(StringUtils.isEmpty(channelId)){
            return new Page<>(checkInPeopleQuery.getPageSize(),checkInPeopleQuery.getPageNo());
        } else {
            if(!"admin".equals(channelId)){
                checkInPeopleQuery.setChannelId(channelId);
            }
        }
        PageInfo<CheckInPeopleListVO> pageInfo =
                PageHelper.startPage(checkInPeopleQuery.getPageNo(), checkInPeopleQuery.getPageSize())
                        .doSelectPageInfo(() -> checkInPeopleDAO
                                .selectPageForMini(checkInPeopleQuery, tokenUser.getSiteId()));
        return new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
    }

    @Override
    public CheckInPeopleDO selectDOById(String checkInPeopleId, String siteId) {
        return listById(checkInPeopleId, siteId);
    }

    @Override
    public List<CheckInPeopleDO> selectDO(CheckInPeopleQuery checkInPeopleQuery, String siteId) {
        Example example = buildExample(checkInPeopleQuery, siteId);
        return checkInPeopleDAO.selectByExample(example);
    }

    @Override
    public List<CheckInPeopleDO> selectListByChannelId(String channelId, String siteId) {
        if (StrKit.isEmpty(channelId)) {
            return new ArrayList<>();
        }
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("channelId", channelId);
        return checkInPeopleDAO.selectByExample(example);
    }

    @Override
    public void setChannelName(List<CheckInPeopleListVO> checkInPeopleListVOList, String siteId) {
        if (CollectionUtils.isEmpty(checkInPeopleListVOList)) {
            return;
        }
        //查询站点下所有的渠道
        List<ChannelListVO> channelListVOList = channelService.select(new ChannelQuery(), siteId);
        Map<String, String> channelIdNameMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(channelListVOList)) {
            channelIdNameMap = channelListVOList.parallelStream().collect(Collectors.toMap(ChannelListVO::getId, ChannelListVO::getName));
        }
        Map<String, String> finalChannelIdNameMap = channelIdNameMap;
        checkInPeopleListVOList.forEach(checkInPeopleListVO -> {
            if (!StringUtils.isEmpty(checkInPeopleListVO.getChannelId()) && finalChannelIdNameMap.containsKey(checkInPeopleListVO.getChannelId())) {
                checkInPeopleListVO.setChannelName(finalChannelIdNameMap.get(checkInPeopleListVO.getChannelId()));
            }
        });
    }

    @Override
    public void setHireDateAndCompanyName(CheckInPeopleListVO checkInPeopleListVO, String siteId) {
        if (StrKit.isEmpty(checkInPeopleListVO.getPhone())) {
            return;
        }
        EmpInfoQuery empInfoQuery = new EmpInfoQuery();
        empInfoQuery.setPhone(checkInPeopleListVO.getPhone());
        List<Order> orders = new ArrayList<>();
        orders.add(new Order("gmtCreate", true));
        empInfoQuery.setOrders(orders);
        List<EmpInfoListVO> empInfoListVOList = empInfoService.select(empInfoQuery, new TokenUser("", siteId));
        if (!CollectionUtils.isEmpty(empInfoListVOList)) {
            checkInPeopleListVO.setJoinDate(empInfoListVOList.get(0).getJoinDate());
            String companyId = empInfoListVOList.get(0).getCompanyId();
            // 查询公司名
            CompanyDO companyDO = companyService.selectDOByIdNotSite(companyId);
            if (Objects.nonNull(companyDO)) {
                checkInPeopleListVO.setCompanyName(companyDO.getName());
            }
        }
    }

    @Override
    public CheckInPeopleDO selectByPhone(String phone, String siteId) {
        if (StrKit.isEmpty(phone)) {
            return null;
        }
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("phone", phone);
        List<CheckInPeopleDO> checkInPeopleDOList = checkInPeopleDAO.selectByExample(example);
        if (!CollectionUtils.isEmpty(checkInPeopleDOList)) {
            return checkInPeopleDOList.get(0);
        } else {
            return null;
        }
    }

    @Override
    public List<CheckInPeopleDO> selectByPhoneList(List<String> phoneList, String siteId) {
        if (CollectionUtils.isEmpty(phoneList)) {
            return new ArrayList<>();
        }
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("phone", phoneList);
        return checkInPeopleDAO.selectByExample(example);
    }

    @Override
    public CheckInPeopleDO selectByName(String name, String siteId) {
        if (StrKit.isEmpty(name)) {
            return null;
        }
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("name", name);
        List<CheckInPeopleDO> checkInPeopleDOList = checkInPeopleDAO.selectByExample(example);
        if (!CollectionUtils.isEmpty(checkInPeopleDOList)) {
            return checkInPeopleDOList.get(0);
        } else {
            return null;
        }
    }

    @Override
    public List<CheckInPeopleDO> selectByPhones(List<String> phones, String siteId) {
        if (CollectionUtils.isEmpty(phones)) {
            return new ArrayList<>();
        }
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("phone", phones);
        return checkInPeopleDAO.selectByExample(example);
    }

    @Override
    public String checkInPeopleExport(CheckInPeopleQuery checkInPeopleQuery, TokenUser tokenUser) {
        Example example = buildExample(checkInPeopleQuery, tokenUser.getSiteId());
        List<CheckInPeopleDO> checkInPeopleDOList = checkInPeopleDAO.selectByExample(example);
        List<CheckInPeopleExportVO> checkInPeopleExportVOList = new ArrayList<>();
        for (CheckInPeopleDO checkInPeopleDO : checkInPeopleDOList) {
            CheckInPeopleExportVO checkInPeopleExportVO;
            checkInPeopleExportVO = checkInPeopleDO.to(CheckInPeopleExportVO.class);
            // 查询渠道名称、状态
            if (StrKit.isNotEmpty(checkInPeopleDO.getChannelId())) {
                ChannelDO channelDO = channelService.selectDOById(checkInPeopleDO.getChannelId(), tokenUser.getSiteId());
                if (Objects.nonNull(channelDO)) {
                    checkInPeopleExportVO.setChannelName(channelDO.getName());
                }
            }
            String statusEum = CheckInPeopleConstant.STATUS_ONE.equals(checkInPeopleExportVO.getStatus()) ?
                    "已接到" : CheckInPeopleConstant.STATUS_TWO.equals(checkInPeopleExportVO.getStatus()) ?
                    "已安排" : CheckInPeopleConstant.STATUS_THREE.equals(checkInPeopleExportVO.getStatus()) ?
                    "已面试" : CheckInPeopleConstant.STATUS_RNTRY.equals(checkInPeopleExportVO.getStatus()) ?
                    "已入职" : CheckInPeopleConstant.STATUS_DIMISSION.equals(checkInPeopleExportVO.getStatus()) ?
                    "已离职" : CheckInPeopleConstant.STATUS_TO_BE_EMPLOYED.equals(checkInPeopleExportVO.getStatus()) ?
                    "待入职" : CheckInPeopleConstant.STATUS_NOT_ON_DUTY.equals(checkInPeopleExportVO.getStatus()) ?
                    "未到岗" : "";
            checkInPeopleExportVO.setStatusEum(statusEum);
            checkInPeopleExportVOList.add(checkInPeopleExportVO);
        }
        return ExcelKit.exportExcel("CheckInPeople", "预登记人员信息", CheckInPeopleExportVO.class, checkInPeopleExportVOList);
    }

    @Override
    public Integer selectCountBySite(TokenUser tokenUser, String filterSource) {
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        if (!StringUtils.isEmpty(filterSource)) {
            example.and().andNotEqualTo("source", filterSource);
        }
        // 判断当前登录人的角色
        String channelId = checkCurrentRole(tokenUser);
        if(!StringUtils.isEmpty(channelId) && !"admin".equals(channelId)){
            example.and().andEqualTo("channelId", channelId);
        }
        return checkInPeopleDAO.selectCountByExample(example);
    }

    /**
     * 判断当前登录的小程序用户是否为管理员或者渠道员
     */
    private String checkCurrentRole(TokenUser tokenUser){
        // 先判断当前登录用户是否是管理员或者渠道员
        ChannelDO channelDO = channelService.selectByUserIdAndSite(tokenUser.getUserId(), tokenUser.getSiteId());
        // 管理员
        List<RoleMemberDO> roleMemberDOList = permissionProviderService
                .selectHrRoleMemberByUserIdAndSiteId(tokenUser.getUserId(), tokenUser.getSiteId());
        // 如果不是管理员
        if(CollectionUtils.isEmpty(roleMemberDOList)){
            if(ObjectUtils.isEmpty(channelDO)){
                return "";
            } else {
                return channelDO.getId();
            }
        }
        return "admin";
    }

    /**
     * 根据查询参数，构建example
     *
     * @param checkInPeopleQuery 查询参数
     * @param siteId             所属站点id
     * @return example
     */
    private Example buildExample(CheckInPeopleQuery checkInPeopleQuery, String siteId) {
        Example example = new Example(CheckInPeopleDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (checkInPeopleQuery.getName() != null) {
            example.and().andLike("name", "%" + checkInPeopleQuery.getName() + "%");
        }
        if (checkInPeopleQuery.getPhone() != null) {
            example.and().andEqualTo("phone", checkInPeopleQuery.getPhone());
        }
        if (checkInPeopleQuery.getIdcard() != null) {
            example.and().andEqualTo("idcard", checkInPeopleQuery.getIdcard());
        }
        if (StrKit.isNotEmpty(checkInPeopleQuery.getChannelId())) {
            if ("无渠道".equals(checkInPeopleQuery.getChannelId())) {
                example.and().andIsNull("channelId");
            } else {
                example.and().andEqualTo("channelId", checkInPeopleQuery.getChannelId());
            }
        }
        if (StrKit.isNotEmpty(checkInPeopleQuery.getNameOrPhoneOrIdcard())) {
            example.and()
                    .orLike("phone", "%" + checkInPeopleQuery.getNameOrPhoneOrIdcard() + "%")
                    .orLike("name", "%" + checkInPeopleQuery.getNameOrPhoneOrIdcard() + "%")
                    .orLike("idcard", "%" + checkInPeopleQuery.getNameOrPhoneOrIdcard() + "%");
        }
        if (StrKit.isNotEmpty(checkInPeopleQuery.getNotSource())) {
            example.and()
                    .andNotEqualTo("source", checkInPeopleQuery.getNotSource());
        }
        if (Boolean.TRUE.equals(checkInPeopleQuery.getIsBatchUpdateStatus())) {
            List<Integer> integers = new ArrayList<>(3);
            integers.add(CheckInPeopleConstant.STATUS_ONE);
            integers.add(CheckInPeopleConstant.STATUS_TWO);
            integers.add(CheckInPeopleConstant.STATUS_THREE);
            example.and().orIn("status", integers)
                    .orIsNull("status");
        }
        if (checkInPeopleQuery.getSource() != null) {
            example.and().andEqualTo("source", checkInPeopleQuery.getSource());
        }
        if (checkInPeopleQuery.getStatus() != null) {
            example.and().andEqualTo("status", checkInPeopleQuery.getStatus());
        }
        if (checkInPeopleQuery.getWorkStatus() != null) {
            example.and().andEqualTo("workStatus", checkInPeopleQuery.getWorkStatus());
        }
        // 排序
        ExampleKit.setExampleOrder(example, checkInPeopleQuery.getOrders());
        return example;
    }
}




